package io.yizoo.system.controller.flow;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.yizoo.business.entity.biz_hrm_ei_basic;
import io.yizoo.business.entity.biz_hrm_ei_rel_org;
import io.elm.core.CoreController;

import java.io.IOException;
import java.util.*;


import io.elm.core.CoreMapper;
import io.elm.core.DMaker;
import io.yizoo.core.flow.FlowDesigner;
import io.yizoo.core.flow.FlowEngine;
import io.yizoo.core.flow.FlowType;
import io.elm.core.security.JwtUtils;
import io.yizoo.core.message.MessageContext;
import io.yizoo.core.message.MessageFactory;
import io.yizoo.core.message.MessageService;
import io.yizoo.system.entity.*;
import io.yizoo.system.mapper.sys_flowMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/system/login/flow")
public class login_flowController extends CoreController {

    @Autowired
    private CoreMapper coreMapper;

    @Autowired
    private FlowDesigner dfTool;

    @Autowired
    private FlowEngine fTool;

    @Autowired
    private sys_flowMapper flowMapper;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private MessageFactory messageFactory;

    //获取流程参数实例值
    //data_id,flow_code
    @PostMapping("/GetFlowinsParam")
    public Object GetFlowinsParam(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String data_id = data.get("data_id").asText();
        String flow_code = data.get("flow_code").asText();
        List<Map<String,Object>> dataList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("data_id",data_id)
                        .putFactorItem("flow_code",flow_code)
                        .Select("param.*")
                        .From(fw_flowins_yw.class,"yw")
                        .innerJoin(fw_flowins_param.class,"param","param.flowins_id = yw.flow_id")
                        .Where("and yw.data_id=#{data_id} and yw.flow_code=#{flow_code}","data_id","flow_code")
                        .GetFactor()
        );
        return GetResultData("success","success",dataList);
    }
    //设置流程参数实例值
    //flow_code,data_id,token
    @Transactional
    @PostMapping("/UpdateFlowinsParam")
    public Object UpdateFlowinsParam(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String nodeins_id = data.get("nodeins_id").asText();
        boolean rB = fTool.UpdateFlowinsParamByNodeinsId(nodeins_id,data);
        if(!rB){ return GetResultData("failure","",null); }
        else{ return GetResultData("success","success",null); }
    }

    //初始化流程
    //flow_code,data_id,token
    //user_id，非必填，不传的话就取当前登录用户的id值
    @PostMapping("/InitFlow")
    public Object InitFlow(@RequestBody String jsonStr) {

        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String flow_code = data.get("flow_code").asText();
        String data_id = data.get("data_id").asText();

        String user_id = FlowType.getJsonNodeItemTextNull(data,"user_id");
        user_id = user_id==null?Ctor.getCurrentUserId():user_id;

        //可能需对参与者接口发起post请求，这里获取token，用来存到post请求的header里从而通过认证检查
        String token = data.get("token").asText();//这里使用前端传入的token,该token通常是在用户登录时生成的
        //String token = jwtUtils.generateToken(Ctor.getCurrentUserId());//按 login/AuthLogin 中的方式，用当前用户id生成一个新token（有新的登录时效）

        //尝试初始化流程
        HashMap<String, Object> result = InitFlow_Tool(data,flow_code,data_id,user_id,token);
        String status= result.get("status").toString();
        if(!status.equals("success")){return result;}

        String first_nodeins_id = ((Map<String, Object>)result.get("data")).get("first_nodeins_id").toString();

        //尝试完成本节点并启动后续，失败不必回滚
        HashMap<String, Object> go_next_result = CompleteNodeins_Tool(first_nodeins_id,user_id,data,token);
        result.put("go_next_result",go_next_result);
        /*
        if(!go_next_result.get("status").equals("success")){
            fTool.DeleteFlowins(data_id);//回滚，即删除相关流程实例
            return GetResultData("failure","启动完成本节点并启动后续时失败",result);
        }
        */

        return GetResultData("success","success",result);
    }

    protected HashMap<String, Object> InitFlow_Tool(ObjectNode data,String flow_code,String data_id,String user_id,String token){

        //流程实例
        fw_flowins flowinsModel = fTool.InitFlow_GetFlowinsModel(flow_code,user_id);
        if(flowinsModel==null){
            return GetResultData("failure","no_flowins",null);
        }
        String flow_id = flowinsModel.getFlow_id();
        String flowins_id = flowinsModel.getId();

        //流程业务关联实例
        fw_flowins_yw flowinsYwModel = new fw_flowins_yw();
        List<Map<String,Object>> checkYwlist = new ArrayList<Map<String,Object>>();
        checkYwlist = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("flow_code",flow_code)
                        .putFactorItem("data_id",data_id)
                        .Select("id")
                        .From(fw_flowins_yw.class,"info")
                        .Where("and info.flow_code=#{flow_code} and info.data_id=#{data_id}","flow_code","data_id")
                        .GetFactor()
        );
        if(checkYwlist.size()>0){
            return GetResultData("failure","flowinsYw_Exist",null);
        }
        flowinsYwModel.setId(UUID.randomUUID().toString());
        flowinsYwModel.setFlow_code(flow_code);
        flowinsYwModel.setData_id(data_id);
        flowinsYwModel.setFlow_id(flowins_id);

        //节点实例
        List<fw_flowins_node> nodeinsModelList = fTool.InitFlow_GetNodeinsModel(flow_id,flowins_id,user_id);
        if(nodeinsModelList==null || nodeinsModelList.size()!=3){
            int nnn = nodeinsModelList==null ? 0 : nodeinsModelList.size();
            return GetResultData("failure","wrong_nodeins_" + nnn,null);
        }

        String first_node_id = nodeinsModelList.get(2).getNode_id();
        String first_nodeins_id = nodeinsModelList.get(2).getId();

        //连线实例
        fw_flowins_line lineinsModel = new fw_flowins_line();
        lineinsModel.setId(UUID.randomUUID().toString());
        lineinsModel.setFlowins_id(flowins_id);
        lineinsModel.setStart_nodeins(nodeinsModelList.get(0).getId());
        lineinsModel.setEnd_nodeins(first_nodeins_id);

        //节点参与者实例
        data.put("flowins_id",flowins_id);
        List<fw_flowins_node_user> nodeinsUserModelList = fTool.GetNodePerson(first_node_id,flowins_id,first_nodeins_id,data,token);
        if(nodeinsUserModelList==null || nodeinsUserModelList.size()==0){
            //流程初始化时，若未查到参与者，那么直接以发起流程的用户为参与者
            fw_flowins_node_user nodeinsUserModel = new fw_flowins_node_user();
            nodeinsUserModel.setId(UUID.randomUUID().toString());
            nodeinsUserModel.setNodeins_id(first_nodeins_id);
            nodeinsUserModel.setUser_id(user_id);
            nodeinsUserModel.setUser_type(FlowType.node_user_type_user);
            nodeinsUserModel.setStatus(FlowType.node_user_status_running);
            nodeinsUserModelList.add(nodeinsUserModel);
            //return GetResultData("failure","no_nodeins_user",null);
        }

        //流程参数数据

        //HashMap<String,Object> some = new HashMap<String,Object>();
        //result.put("flowinsModel",flowinsModel);
        //result.put("nodeinsModelList",nodeinsModelList);
        //result.put("nodeinsModelList",nodeinsModelList);
        //some.put("nodeinsUserModelList",nodeinsUserModelList);
        //if(true){return some;}

        //添加流程参数实例
        fTool.UpdateFlowinsParam(flow_id,flowins_id,data);

        //实例化流程、流程与业务关联、流程节点、节点参与者、连线
        flowinsModel.setSys_code_key("");
        Ctor.HMapper.Upsert(flowinsModel);
        Ctor.HMapper.Upsert(flowinsYwModel);
        if(nodeinsModelList.size()==3){
            Ctor.HMapper.Save(nodeinsModelList,null);
            Ctor.HMapper.Upsert(fTool.CreateNodeLogModel(nodeinsModelList.get(2),user_id,0));
            Ctor.HMapper.Upsert(lineinsModel);
        }
        if(nodeinsUserModelList.size()>0){Ctor.HMapper.Save(nodeinsUserModelList,null);}

        //组装返回数据
        HashMap<String, Object> result = new HashMap<String, Object>();
        result.put("flow_id",flowins_id);
        result.put("flowins_id",flowins_id);
        result.put("first_node_id",first_node_id);
        result.put("first_nodeins_id",first_nodeins_id);
        result.put("first_nodeins_user_num",nodeinsUserModelList.size());
        List<Map<String,Object>> checkNodelist = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("id",first_nodeins_id)
                        .Select("status")
                        .From(fw_flowins_node.class)
                        .Where("and id=#{id}","id")
                        .GetFactor()
        );

        return GetResultData("success","success",result);
    }

    //完成一个节点实例
    //nodeins_id,token
    //user_id，非必填，不传的话就取当前登录用户的id值
    //用于动态指定节点参与者的两参数： dynamic_node_id、dynamic_user_id
    //其中 dynamic_node_id 中多个节点id用分号分隔，dynamic_user_id 中多个节点的参与者id用分号分隔，同节点的多个参与者id用逗号分隔
    @PostMapping("/CompleteNodeins")
    public Object CompleteNodeins(@RequestBody String jsonStr){
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String nodeins_id = data.get("nodeins_id").asText();
        String user_id = FlowType.getJsonNodeItemTextNull(data,"user_id");
        user_id = user_id==null?Ctor.getCurrentUserId():user_id;

        //可能需对参与者接口发起post请求，这里获取token，用来存到post请求的header里从而通过认证检查
        String token = data.get("token").asText();//这里使用前端传入的token,该token通常是在用户登录时生成的
        //String token = jwtUtils.generateToken(Ctor.getCurrentUserId());//按 login/AuthLogin 中的方式，用当前用户id生成一个新token（有新的登录时效）

        //更新流程参数实例
        fTool.UpdateFlowinsParamByNodeinsId(nodeins_id,data);

        //完成节点实例
        HashMap<String,Object> result = CompleteNodeins_Tool(nodeins_id,user_id,data,token);

        return result;
    }

    //完成一个节点实例
    protected HashMap<String, Object> CompleteNodeins_Tool(String nodeins_id, String user_id,ObjectNode data, String token){
        String node_id = "nothing";
        String flowins_id = "nothing";

        //验证参与者权限
        boolean isNodeUser = false;
        boolean isNodeRunningUser = false;
        String nodePolicy = "";
        List<String> nUserIdNeedOver = new ArrayList<String>();
        List<Map<String,Object>> nCheckInfoList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("user_id",user_id)
                        .putFactorItem("nodeins_id",nodeins_id)
                        .Select("uu.id,uu.dept_id AS org_id,nodeins.node_policy,nodeins.node_id,nodeins.flowins_id,yw.data_id")
                        .From(sys_user.class,"uu")
                        .innerJoin(fw_flowins_node.class,"nodeins","nodeins.id = #{nodeins_id} AND nodeins.status = '"+FlowType.node_status_running+"'","nodeins_id")
                        .innerJoin(fw_flow_node.class,"node","node.id=nodeins.node_id")
                        .innerJoin(fw_flowins_yw.class,"yw","yw.flow_id = nodeins.flowins_id")
                        .Where("AND uu.id = #{user_id}","user_id")
                        .GetFactor()
        );
        if(nCheckInfoList.size()==0){return GetResultData("failure", "c_node_no_data", null);}
        nodePolicy = nCheckInfoList.get(0).get("node_policy").toString();
        node_id = nCheckInfoList.get(0).get("node_id").toString();
        flowins_id = nCheckInfoList.get(0).get("flowins_id").toString();
        List<Map<String,Object>> nodePersonList = fTool.SearchNodeinsPerson(nodeins_id);
        if(nodePersonList.size()==0){return GetResultData("failure", "no_node_user", null);}
        boolean otherRunningPersonExist = false;
        for(Map<String,Object> person : nodePersonList){
            boolean pCheck = person.get("user_id").toString().equals(user_id);
            boolean thisUserRunning = person.get("status")==null || !(person.get("status").toString().equals(FlowType.node_user_status_completed));
            if(pCheck){
                isNodeUser = true;
                if(thisUserRunning){
                    isNodeRunningUser = true;
                    nUserIdNeedOver.add(person.get("id").toString());
                }
            }
            else{ otherRunningPersonExist = thisUserRunning; }
        }
        if(!isNodeUser){ return GetResultData("failure", "notNodeUser", null); }
        else if(!isNodeRunningUser){ return GetResultData("failure", "isNodeUserButNotRunning", null); }
        List<fw_flowins_node_user> nUserModelList = new ArrayList<fw_flowins_node_user>();
        for(String nUId : nUserIdNeedOver){
            fw_flowins_node_user nUserModel = new fw_flowins_node_user();
            nUserModel.setId(nUId);
            nUserModel.setStatus(FlowType.node_user_status_completed);
            nUserModel.setStatus_time(new Date());

            nUserModelList.add(nUserModel);
        }
        //对于各种类型的参与者表记录，只要能跟user_id对应就视为本条记录完成
        //这样处理后，若参与者策略为会签且还有未完成的参与者，那么更新完成参与者的状态并返回，不更新节点状态
        boolean waitingOtherPerson = nodePolicy.equals(FlowType.node_policy_need_every_user) && otherRunningPersonExist;
        if(waitingOtherPerson){
            //更新参与者状态
            if(nUserModelList.size()>0){ Ctor.HMapper.Save(nUserModelList,null); }
            System.out.println("【AAAA】更新"+nUserModelList.size()+"个参与者状态为完成，等待其他参与者  【BBBB】nodeins_id: "+nodeins_id);

            //添加节点日志，此时节点状态并未变化
            fw_flowins_node_log nodeinsLogModel = new fw_flowins_node_log();
            nodeinsLogModel.setId(UUID.randomUUID().toString());
            nodeinsLogModel.setNodeins_id(nodeins_id);
            nodeinsLogModel.setStatus("submit_no_change");
            nodeinsLogModel.setStatus_user(user_id);
            nodeinsLogModel.setStatus_time(new Date());
            nodeinsLogModel.setStatus_timestamp("" + ( System.currentTimeMillis()));
            Ctor.HMapper.Upsert(nodeinsLogModel);

            //结束并返回成功信息
            return GetResultData("success", "waitingOtherUser", null);
        }

        //用于更新的节点实例数据
        fw_flowins_node nodeinsModel = new fw_flowins_node();
        nodeinsModel.setId(nodeins_id);
        nodeinsModel.setStatus(FlowType.node_status_completed);

        //查找连线和后续节点数据，包括已实例化的后续节点信息（如果有）
        List<Map<String,Object>> nextNodeList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("node_id",node_id)
                        .Select("node.node_type,line.condition_s AS line_condition,line.text AS line_text,line.type AS line_type,line.remark as line_remark,node.id AS node_id,node.*")
                        .From(fw_flow_line.class,"line")
                        .innerJoin(fw_flow_node.class,"node","node.ID = line.end_node")
                        .Where("AND line.start_node = #{node_id}","node_id")
                        .OrderBy("node.remark")
                        .GetFactor()
        );
        if(nextNodeList.size()==0){ return GetResultData("failure", "noNextNode", null); }

        //用于动态指定节点参与者的数据
        Map<String,String> dynamicNodeUserId = new HashMap<String,String>();
        if(data.has("dynamic_user_id") && data.has("dynamic_node_id")){
            String dynamic_node_id = FlowType.getJsonNodeItemTextNull(data,"dynamic_node_id");
            String dynamic_user_id = FlowType.getJsonNodeItemTextNull(data,"dynamic_user_id");
            if(dynamic_user_id!=null && dynamic_user_id!=null){
                String[] nIdList = dynamic_node_id.split(";");
                String[] uIdList = dynamic_user_id.split(";");
                if(nIdList.length == uIdList.length){
                    for(int i=0;i<nIdList.length;i++){
                        dynamicNodeUserId.put(nIdList[i],uIdList[i]);
                    }
                }
            }
        }

        //验证连线条件，获取应启动的后续节点
        //组装相应连线和节点实例数据
        int nextNodeNum = 0;
        List<Map<String,String>> needDynamicUserNodeList = new ArrayList<Map<String,String>>();
        List<fw_flowins_line> lineinsModelList = new ArrayList<fw_flowins_line>();
        List<fw_flowins_node> nextNodeinsModelList = new ArrayList<fw_flowins_node>();
        List<fw_flowins_node_user> nextNodeinsUserModelList = new ArrayList<fw_flowins_node_user>();
        List<String> nextNodeinsIdList_Completed = new ArrayList<String>();
        List<String> nextRunningNodeinsIdList_SamePerson = new ArrayList<String>();
        for(int i=0;i<nextNodeList.size();i++){
            Map<String,Object> nextNode = nextNodeList.get(i);

            String lineCondition = nextNode.get("line_condition")==null ? null : nextNode.get("line_condition").toString();
            String nextNodeId = nextNode.get("node_id").toString();
            String nextNodeCheck = fTool.StartNodeByLineCondition_Check(lineCondition,flowins_id,nextNodeId,data);

            //若应启动的后续节点中有结束节点，那么流程结束
            if(nextNodeCheck.equals("yes") || nextNodeCheck.startsWith("no_nodeInsExist")){
                if(nextNode.get("node_type").toString().equals(FlowType.node_type_end)){
                    //更新参与者状态
                    if(nUserModelList.size()>0){ Ctor.HMapper.Save(nUserModelList,null); }
                    //更新节点状态
                    Ctor.HMapper.Upsert(nodeinsModel);
                    Ctor.HMapper.Upsert(fTool.CreateNodeLogModel(nodeinsModel,user_id,1));
                    //更新流程状态
                    fw_flowins flowinsModel = new fw_flowins();
                    flowinsModel.setId(flowins_id);
                    flowinsModel.setStatus(FlowType.flow_status_completed);
                    Ctor.HMapper.Upsert(flowinsModel);

                    System.out.println("【AAAA】后续节点中存在结束节点，流程结束  【BBBB】nodeins_id: "+nodeins_id);

                    //结束并返回成功信息
                    return GetResultData("success", "flowOver", null);
                }
            }

            if(nextNodeCheck.equals("yes")){
                nextNodeNum++;

                fw_flowins_node nextNodeModel = new fw_flowins_node();
                nextNodeModel.setId(UUID.randomUUID().toString());
                nextNodeModel.setFlowins_id(flowins_id);
                nextNodeModel.setTitle(nextNode.get("title")==null?null:nextNode.get("title").toString());
                nextNodeModel.setNode_id(nextNode.get("node_id")==null?null:nextNode.get("node_id").toString());
                nextNodeModel.setNode_type(nextNode.get("node_type")==null?null:nextNode.get("node_type").toString());
                nextNodeModel.setRemark(nextNode.get("remark")==null?null:nextNode.get("remark").toString());
                nextNodeModel.setStatus(FlowType.node_status_running);
                nextNodeModel.setNode_alias(nextNode.get("node_alias")==null?null:nextNode.get("node_alias").toString());
                nextNodeModel.setNode_policy(nextNode.get("node_policy")==null?null:nextNode.get("node_policy").toString());
                nextNodeModel.setUser_policy(nextNode.get("user_policy")==null?null:nextNode.get("user_policy").toString());
                nextNodeModel.setPb_policy(nextNode.get("pb_policy")==null?null:nextNode.get("pb_policy").toString());
                nextNodeModel.setSys_createtime(new Date());
                nextNodeModel.setSys_createtimestamp("" + System.currentTimeMillis());
                nextNodeinsModelList.add(nextNodeModel);

                fw_flowins_line lineinsMode = new fw_flowins_line();
                lineinsMode.setId(UUID.randomUUID().toString());
                lineinsMode.setFlowins_id(flowins_id);
                lineinsMode.setCondition_s(lineCondition);
                lineinsMode.setStart_nodeins(nodeins_id);
                lineinsMode.setEnd_nodeins(nextNodeModel.getId());
                lineinsMode.setType(nextNode.get("line_type")==null?null:nextNode.get("line_type").toString());
                lineinsMode.setText(nextNode.get("line_text")==null?null:nextNode.get("line_text").toString());
                lineinsMode.setRemark(nextNode.get("line_remark")==null?null:nextNode.get("line_remark").toString());
                lineinsModelList.add(lineinsMode);

                //若应启动的后续节点中，有需要按本次提交传入的 dynamic_user_id 来确认参与者的节点，那么检查是否传入了对应的 dynamic_user_id
                //dynamic_user_id 中包含的 user_id 个数应与这类节点个数相等，若不相等，那么返回提示信息
                //若相等，则组装数据供后续确认参与者使用

                data.put("previous_nodeins_id",nodeins_id);
                data.put("flowins_id",flowins_id);
                if(dynamicNodeUserId.containsKey(nextNodeModel.getNode_id())){
                    data.put("dynamic_user_id",dynamicNodeUserId.get(nextNodeModel.getNode_id()));
                }
                List<fw_flowins_node_user> nuList = fTool.GetNodePerson(nextNodeModel.getNode_id(),flowins_id,nextNodeModel.getId(),data,token);
                if(nuList==null){//需动态指定节点参与者，而未传入相应参数 的情况
                    Map<String,String> needDynamicUserNodeData = new HashMap<String, String>();
                    needDynamicUserNodeData.put("id",nextNodeModel.getNode_id());
                    needDynamicUserNodeData.put("title",nextNodeModel.getTitle());
                    needDynamicUserNodeList.add(needDynamicUserNodeData);
                }
                else if(nuList.size()==0){
                    return GetResultData("failure", "noNextNodeUser", nextNodeModel.getTitle());
                }
                else{
                    for(fw_flowins_node_user nu : nuList){ nextNodeinsUserModelList.add(nu); }

                    //检查节点参与者是否包括本次提交的用户，若包括，那么后面将其提交完成
                    if(fTool.IsNodeRunningPerson(nuList,user_id)){nextRunningNodeinsIdList_SamePerson.add(nextNodeModel.getId());}
                }
            }
            else if(nextNodeCheck.equals("no_lineConditionFalse")){}
            else if(nextNodeCheck.startsWith("no_nodeInsExist")){
                //已实例化的节点不再次启动，也计入nextNodeNum中
                nextNodeNum++;

                //对于这类节点中处于已完成或退回等待的部分，记录一下其ID，供后面处理相关退回数据（如果有）时使用
                if(nextNodeCheck.endsWith(FlowType.node_status_completed) || nextNodeCheck.endsWith(FlowType.node_status_waiting)){
                    String[] ncStrList = nextNodeCheck.split("--");
                    if(ncStrList.length==3){
                        nextNodeinsIdList_Completed.add(ncStrList[1]);
                    }
                }
                //对于这类节点中处于运行中的部分，检查节点参与者是否包括本次提交的用户，若包括，那么后面将其提交完成
                if(nextNodeCheck.endsWith(FlowType.node_status_running)){
                    String[] ncStrList = nextNodeCheck.split("--");
                    if(ncStrList.length==3){
                        if(fTool.IsRunningNodeRunningPerson(ncStrList[1],user_id)){nextRunningNodeinsIdList_SamePerson.add(ncStrList[1]);}
                    }
                }
            }
            else{ return GetResultData("failure", nextNodeCheck, null); }
        }
        //若没有应启动的后续节点，那么不更新数据并返回错误信息
        if(nextNodeNum<=0) { return GetResultData("failure", "noNextNode", null); }
        //若需动态指定节点参与者，而未传入相应参数，那么不更新数据并返回提示信息
        if(needDynamicUserNodeList.size()>0){
            return GetResultData("failure", "needDynamicUser", needDynamicUserNodeList);
        }

        //检查退回信息，若有指向本节点的未完成的退回信息，那么做结束退回的处理
        boolean pbExist=false;
        List<fw_flowins_node_back> pbOver_NodeBackModelList = new ArrayList<fw_flowins_node_back>();
        List<fw_flowins_node> pbOver_FromNodeModelList = new ArrayList<fw_flowins_node>();
        List<fw_flowins_node_user> pbOver_FromNodeUserModelList = new ArrayList<fw_flowins_node_user>();
        List<fw_flowins_node> pbOver_NextNodeModelList = new ArrayList<fw_flowins_node>();
        List<fw_flowins_node_user> pbOver_NextNodeUserModellList = new ArrayList<fw_flowins_node_user>();
        List<Map<String,Object>> pushBackDataList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("nodeins_id",nodeins_id)
                        .putFactorItem("pb_status", FlowType.node_push_back_status_running)
                        .Select("pb.id,from_node.pb_policy AS from_nodeins_pb_policy,from_node.id AS from_nodeins_id,from_node.status AS from_nodeins_status")
                        .From(fw_flowins_node_back.class,"pb")
                        .innerJoin(fw_flowins_node.class,"from_node","from_node.id = pb.from_nodeins")
                        .Where("AND pb.to_nodeins = #{nodeins_id} AND pb.status = #{pb_status}","nodeins_id","pb_status")
                        .OrderBy("pb.sys_createtime DESC")
                        .GetFactor()
        );
        System.out.println("【节点完成】有" + pushBackDataList.size() + "条退回信息");
        if(pushBackDataList.size()>0){
            for(Map<String,Object> pushBackData : pushBackDataList){
                fw_flowins_node_back pbOver_NodeBackModel = new fw_flowins_node_back();
                pbOver_NodeBackModel.setId(pushBackData.get("id").toString());
                pbOver_NodeBackModel.setStatus(FlowType.node_push_back_status_completed);
                pbOver_NodeBackModel.setStatus_time(new Date());
                pbOver_NodeBackModelList.add(pbOver_NodeBackModel);
                if(pushBackData.get("from_nodeins_status").toString().equals(FlowType.node_status_waiting)){
                    pbExist = true;

                    String pbPolicy = pushBackData.get("from_nodeins_pb_policy").toString();
                    if(
                            pbPolicy.equals(FlowType.node_pb_policy_toFirst_eJump)
                            || pbPolicy.equals(FlowType.node_pb_policy_toSelected_eJump)
                            || pbPolicy.equals(FlowType.node_pb_policy_toLast_eJump)
                    )
                    {
                        //若退回策略为跳回，那么将发起退回的节点实例和相应参与者重启
                        fw_flowins_node pbFromNodeModel = new fw_flowins_node();
                        String from_nodeins_id = pushBackData.get("from_nodeins_id").toString();
                        pbFromNodeModel.setId(from_nodeins_id);
                        pbFromNodeModel.setStatus(FlowType.node_status_running);
                        List<Map<String,Object>> fromNodeUserList = coreMapper.USelectList(
                                new DMaker().Selector
                                        .putFactorItem("from_nodeins_id",from_nodeins_id)
                                        .Select("id,status")
                                        .From(fw_flowins_node_user.class)
                                        .Where("AND nodeins_id = #{from_nodeins_id}","from_nodeins_id")
                                        .GetFactor()
                        );
                        pbOver_FromNodeModelList.add(pbFromNodeModel);
                        for(Map<String,Object> fromNodeUserData : fromNodeUserList){
                            if(fromNodeUserData.get("status").toString().equals(FlowType.node_user_status_waiting)){
                                fw_flowins_node_user pbFromNodeUserModel = new fw_flowins_node_user();
                                pbFromNodeUserModel.setId(fromNodeUserData.get("id").toString());
                                pbFromNodeUserModel.setStatus(FlowType.node_user_status_running);
                                pbOver_FromNodeUserModelList.add(pbFromNodeUserModel);
                            }
                        }
                    }
                    else{
                        //若退回策略为顺回，那么按退回指向节点实例（即本节点实例）的后续连线条件判断应该启动的后续节点
                        //连线判断的部分，已经在前面完成节点并启动后续时进行过了
                        //未实例化的连线、节点、参与者的实例数据，也在前面完成节点并启动后续时组装了
                        //对于后续节点中已完成的节点实例，应重启节点实例和参与者实例
                        if(nextNodeinsIdList_Completed.size()>0){
                            for(String nc_nodeins_id : nextNodeinsIdList_Completed){
                                fw_flowins_node pbNextNodeModel = new fw_flowins_node();
                                pbNextNodeModel.setId(nc_nodeins_id);
                                pbNextNodeModel.setStatus(FlowType.node_status_running);
                                List<Map<String,Object>> nextNodeUserList = coreMapper.USelectList(
                                        new DMaker().Selector
                                                .putFactorItem("nc_nodeins_id",nc_nodeins_id)
                                                .Select("id,status")
                                                .From(fw_flowins_node_user.class)
                                                .Where("AND nodeins_id = #{nc_nodeins_id}","nc_nodeins_id")
                                                .GetFactor()
                                );
                                pbOver_NextNodeModelList.add(pbNextNodeModel);
                                for(Map<String,Object> nextNodeUserData : nextNodeUserList){
                                    if(!nextNodeUserData.get("status").toString().equals(FlowType.node_user_status_running)){
                                        fw_flowins_node_user pbNextNodeUserModel = new fw_flowins_node_user();
                                        pbNextNodeUserModel.setId(nextNodeUserData.get("id").toString());
                                        pbNextNodeUserModel.setStatus(FlowType.node_user_status_running);
                                        pbOver_NextNodeUserModellList.add(pbNextNodeUserModel);
                                    }
                                }
                            }
                        }
                    }

                }
            }
        }

        //if(true){return GetResultData("test", "测试", null);}

        //更新参与者状态
        if(nUserModelList.size()>0){Ctor.HMapper.Save(nUserModelList,null);}
        //更新节点状态
        Ctor.HMapper.Upsert(nodeinsModel);
        Ctor.HMapper.Upsert(fTool.CreateNodeLogModel(nodeinsModel,user_id,1));
        //后续节点-连线实例化
        if(lineinsModelList.size()>0){Ctor.HMapper.Save(lineinsModelList,null);}
        //后续节点-节点实例化
        if(nextNodeinsModelList.size()>0){
            Ctor.HMapper.Save(nextNodeinsModelList,null);
            Ctor.HMapper.Save(fTool.CreateNodeLogModelList(nextNodeinsModelList,user_id,2),null);
        }
        //后续节点-节点参与者实例化
        if(nextNodeinsUserModelList.size()>0){Ctor.HMapper.Save(nextNodeinsUserModelList,null);}
        if(pbExist){
            if(pbOver_NodeBackModelList.size()>0){ Ctor.HMapper.Save(pbOver_NodeBackModelList,null); }
            if(pbOver_FromNodeModelList.size()>0){
                Ctor.HMapper.Save(pbOver_FromNodeModelList,null);
                Ctor.HMapper.Save(fTool.CreateNodeLogModelList(pbOver_FromNodeModelList,user_id,3),null);
            }
            if(pbOver_FromNodeUserModelList.size()>0){Ctor.HMapper.Save(pbOver_FromNodeUserModelList,null);}
            if(pbOver_NextNodeModelList.size()>0){
                Ctor.HMapper.Save(pbOver_NextNodeModelList,null);
                Ctor.HMapper.Save(fTool.CreateNodeLogModelList(pbOver_NextNodeModelList,user_id,4),null);
            }
            if(pbOver_NextNodeUserModellList.size()>0){Ctor.HMapper.Save(pbOver_NextNodeUserModellList,null);}
        }

        //推送提醒消息
        if(nextNodeinsModelList.size()>0){
            String ei_name = "";
            String flow_name = "";
            List<Map<String,Object>> mList = coreMapper.USelectList(
                    new DMaker().Selector
                            .putFactorItem("user_id",user_id)
                            .putFactorItem("nodeins_id",nodeins_id)
                            .Select("ei.name AS ei_name,flowins.title AS flow_name")
                            .From(sys_user.class,"uu")
                            .innerJoin(biz_hrm_ei_basic.class,"ei","ei.emp_code = uu.emp_code")
                            .innerJoin(fw_flowins_node.class,"nodeins","nodeins.id = #{nodeins_id}","nodeins_id")
                            .innerJoin(fw_flowins.class,"flowins","flowins.id=nodeins.flowins_id")
                            .Where("AND uu.id = #{user_id}","user_id")
                            .GetFactor()
            );
            if(mList.size()>0){
                ei_name = mList.get(0).get("ei_name").toString();
                flow_name = mList.get(0).get("flow_name").toString();
            }
            try {
                String m_title = "待办提醒";
                String m_content = "您有一条 "+ei_name+" 的 "+flow_name+" 流程需要处理";
                String sendUserId = user_id;
                List<String> m_user_id = new ArrayList<String>();
                for(fw_flowins_node m_node:nextNodeinsModelList){
                    Map<String,Object> pData = new HashMap<String,Object>();
                    pData.put("nodeins_id",m_node.getId());
                    List<Map<String,Object>> checkList = flowMapper.GetUserIdByNodeInsIdAndNodeinsUser(pData);
                    for(Map<String,Object> check : checkList){
                        m_user_id.add(check.get("user_id").toString());
                    }
                }

                String currentKey = Ctor.getCurrentKey();
                MessageContext context = new MessageContext(
                        currentKey,
                        m_user_id,
                        m_title,
                        m_content,
                        false,
                        sendUserId
                );
                MessageService instance = messageFactory.getInstance(sendUserId);
                String result = instance.sendMsg(context);
                result = "";
            }catch (Exception e){e.printStackTrace();}
        }

        //对于后续被启动的节点，若其参与者包括本次提交的用户，那么将其提交完成
        //注意，如果传入了 no_auto_next 参数，不做递归
        //注意，如果传入了 f_param_user_id 参数或 dynamic_user_id 参数，此时认为存在指定节点参与者的情况，为了不影响后面可能的递归节点，此时不做递归
        if(!data.has("no_auto_next")
                && !data.has("f_param_user_id") && !data.has("dynamic_user_id")
                && nextRunningNodeinsIdList_SamePerson.size()>0){
            try {
                for(String nextRunningNodeinsId : nextRunningNodeinsIdList_SamePerson){
                    HashMap<String,Object> rComplete = CompleteNodeins_Tool(nextRunningNodeinsId,user_id,data,token);
                    if(rComplete.containsKey("message") && rComplete.get("message").equals("flowOver")){return rComplete;}
                }
            }catch (Exception e){e.printStackTrace();}
        }

        HashMap<String,Object> rData = new HashMap<String,Object>();
        rData.put("addNextNodeNum",nextNodeinsModelList.size());
        return GetResultData("success", "nodeComplete", rData);
    }

    //设置节点实例的参与者
    //nodeins_id
    //node_user_list，格式类似 [{'user_type':'user','user_id':'1'}]}
    @PostMapping("/SetNodeinsUser")
    public Object SetNodeinsUser(@RequestBody String jsonStr) {
        String flowins_id = "nothing";

        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String nodeins_id = data.get("nodeins_id").asText();
        ArrayNode node_user_list = (ArrayNode)data.get("node_user_list");
        if(node_user_list.size()==0){
            return GetResultData("failure","no_node_user",null);
        }

        List<Map<String,Object>> nCheckList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("nodeins_id",nodeins_id)
                        .Select("id")
                        .From(fw_flowins_node.class)
                        .Where("AND id = #{nodeins_id}","nodeins_id")
                        .GetFactor()
        );
        if(nCheckList.size()==0){
            return GetResultData("failure","no_nodeins",null);
        }

        String keepNodeinsUserId = "nothing,";
        List<fw_flowins_node_user> nUserModelList = new ArrayList<fw_flowins_node_user>();
        for(JsonNode node_user : node_user_list){
            String user_type = node_user.get("user_type").asText();
            String user_id = node_user.get("user_id").asText();
            List<Map<String,Object>> uCheckList = coreMapper.USelectList(
                    new DMaker().Selector
                            .putFactorItem("nodeins_id",nodeins_id)
                            .putFactorItem("user_type",user_type)
                            .putFactorItem("user_id",user_id)
                            .Select("id")
                            .From(fw_flowins_node_user.class)
                            .Where("AND nodeins_id = #{nodeins_id} AND user_type = #{user_type} AND user_id = #{user_id}","nodeins_id","user_type","user_type")
                            .GetFactor()
            );
            if(uCheckList.size()==0){
                fw_flowins_node_user nUserModel = new fw_flowins_node_user();
                nUserModel.setId(UUID.randomUUID().toString());
                nUserModel.setNodeins_id(nodeins_id);
                nUserModel.setUser_type(user_type);
                nUserModel.setUser_id(user_id);
                nUserModel.setStatus(FlowType.node_user_status_running);
                nUserModelList.add(nUserModel);
            }
            else{
                //已存在的参与者实例不处理
                keepNodeinsUserId = keepNodeinsUserId  + uCheckList.get(0).get("id").toString()+ ",";
            }
        }

        //更新参与者
        Ctor.CoreMapper.UDelete(
                Ctor.DMaker(jsonStr).Deleter
                        .putFactorItem("nodeins_id",nodeins_id)
                        .putFactorItem("keep_id",keepNodeinsUserId)
                        .From(fw_flowins_node_user.class)
                        .Where("AND nodeins_id = #{nodeins_id} AND INSTR(#{keep_id}, CONCAT(CONCAT(',',id),',')) = 0 ", "nodeins_id","keep_id")
                        .GetFactor());
        if(nUserModelList.size()>0){ Ctor.HMapper.Save(nUserModelList,null); }

        return GetResultData("success","success",null);
    }

    //判断节点实例是否可以退回
    //nodeins_id
    @PostMapping("/CheckPushBackAllow")
    public Object CheckPushBackAllow(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String nodeins_id = data.get("nodeins_id").asText();

        List<Map<String,Object>> nCheckList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("nodeins_id",nodeins_id)
                        .Select("node.pb_policy,nodeins.status,previous_nodeins.node_type as previous_node_type,IFNULL(pb.id,'nothing') AS pb_id")
                        .From(fw_flowins_node.class,"nodeins")
                        .innerJoin(fw_flow_node.class,"node","node.id=nodeins.node_id")
                        .LeftJoin(fw_flowins_line.class,"line","line.end_nodeins=nodeins.id")
                        .LeftJoin(fw_flowins_node.class,"previous_nodeins","line.start_nodeins=previous_nodeins.id")
                        .LeftJoin(fw_flowins_node_back.class,"pb","pb.from_nodeins=previous_nodeins.id AND pb.status='running'")
                        .Where("AND nodeins.id = #{nodeins_id}","nodeins_id")
                        .GetFactor()
        );

        if(nCheckList.size()==0){return "no";}//找不到节点信息的情况
        for(Map<String,Object> nCheck :nCheckList){
            if(nCheck.get("pb_policy").toString().equals(FlowType.node_pb_policy_No)){return "no";}//节点禁止退回的情况
            if(!(nCheck.get("status").toString().equals(FlowType.node_status_running))){return "no";}//节点并非运行中的情况
            if(nCheck.get("previous_node_type").toString().equals(FlowType.node_type_start)){return "no";}//节点为初始节点的情况
            if(!(nCheck.get("pb_id").toString().equals("nothing"))){return "no";}//存在从本节点发起的尚未结束的退回数据的情况
        }
        return "yes";
    }

    //查找指向节点实例且未结束的退回信息
    //nodeins_id
    @PostMapping("/SearchRunningPbtoNodeins")
    public Object SearchRunningPbtoNodeins(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String nodeins_id = data.get("nodeins_id").asText();

        List<Map<String,Object>> nCheckList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("nodeins_id",nodeins_id)
                        .Select("pb.text,pb.sys_createtime")
                        .From(fw_flowins_node_back.class,"pb")
                        .Where(" AND pb.status='running' AND pb.to_nodeins = #{nodeins_id}","nodeins_id")
                        .GetFactor()
        );

        return nCheckList;
    }

    //退回
    //nodeins_id,pb_text,token
    //back_to_nodeins_id，用于手选退回，多个id用“,”分隔
    //user_id，非必填，不传的话就取当前登录用户的id值
    @PostMapping("/PushBackToNodeins")
    public Object PushBackToNodeins(@RequestBody String jsonStr) {
        String flowins_id = "nothing";

        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        String nodeins_id = data.get("nodeins_id").asText();
        String user_id = FlowType.getJsonNodeItemTextNull(data,"user_id");
        user_id = user_id==null?Ctor.getCurrentUserId():user_id;
        String pb_text = data.get("pb_text").asText();
        String pb_to_nodeins_id = null;
        if(data.has("back_to_nodeins_id") && data.get("back_to_nodeins_id")!=null){
            pb_to_nodeins_id = data.get("back_to_nodeins_id").asText();
        }

        //可能需对参与者接口发起post请求，这里获取token，用来存到post请求的header里从而通过认证检查
        String token = data.get("token").asText();//这里使用前端传入的token,该token通常是在用户登录时生成的
        //String token = jwtUtils.generateToken(Ctor.getCurrentUserId());//按 login/AuthLogin 中的方式，用当前用户id生成一个新token（有新的登录时效）

        //验证参与者权限
        boolean isNodeUser = false;
        boolean isNodeRunningUser = false;
        String pbPolicy = "";
        String flow_id = "";
        String pb_from_node_id = "";
        List<String> nUserIdNeedWaiting = new ArrayList<String>();
        List<Map<String,Object>> nCheckInfoList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("user_id",user_id)
                        .putFactorItem("nodeins_id",nodeins_id)
                        .Select("uu.id,uu.dept_id AS org_id,nodeins.flowins_id,nodeins.status,node.flow_id,nodeins.node_id,nodeins.pb_policy,yw.data_id")
                        .From(sys_user.class,"uu")
                        .innerJoin(fw_flowins_node.class,"nodeins","nodeins.id = #{nodeins_id} AND nodeins.status = '"+FlowType.node_status_running+"'","nodeins_id")
                        .innerJoin(fw_flow_node.class,"node","node.id=nodeins.node_id")
                        .innerJoin(fw_flowins_yw.class,"yw","yw.flow_id = nodeins.flowins_id")
                        .Where("AND uu.id = #{user_id}","user_id")
                        .GetFactor()
        );
        if(nCheckInfoList.size()==0){return GetResultData("failure", "c_node_no_data", null);}
        if((nCheckInfoList.get(0).get("status").toString().equals(FlowType.node_status_waiting))){return GetResultData("failure", "节点处于退回等待状态", null);}
        flow_id = nCheckInfoList.get(0).get("flow_id").toString();
        pb_from_node_id = nCheckInfoList.get(0).get("node_id").toString();
        flowins_id = nCheckInfoList.get(0).get("flowins_id").toString();
        pbPolicy = nCheckInfoList.get(0).get("pb_policy").toString();
        List<Map<String,Object>> nodePersonList = fTool.SearchNodeinsPerson(nodeins_id);
        if(nodePersonList.size()==0){return GetResultData("failure", "no_node_user", null);}
        for(Map<String,Object> person : nodePersonList){
            boolean pCheck = person.get("user_id").toString().equals(user_id);
            boolean thisUserRunning = person.get("status")==null || !(person.get("status").toString().equals(FlowType.node_user_status_completed));
            if(pCheck){
                isNodeUser = true;
                if(thisUserRunning){
                    isNodeRunningUser = true;
                    nUserIdNeedWaiting.add(person.get("id").toString());
                }
            }
        }
        if(!isNodeUser){ return GetResultData("failure", "notNodeUser", null); }
        else if(!isNodeRunningUser){ return GetResultData("failure", "isNodeUserButNotRunning", null); }
        List<fw_flowins_node_user> nUserWaitingModelList = new ArrayList<fw_flowins_node_user>();
        for(String nUId : nUserIdNeedWaiting){
            fw_flowins_node_user nUserModel = new fw_flowins_node_user();
            nUserModel.setId(nUId);
            nUserModel.setStatus(FlowType.node_user_status_waiting);
            nUserModel.setStatus_time(new Date());

            nUserWaitingModelList.add(nUserModel);
        }
        fw_flowins_node nodeinsWaitingModel = new fw_flowins_node();
        nodeinsWaitingModel.setId(nodeins_id);
        nodeinsWaitingModel.setStatus(FlowType.node_status_waiting);

        //按退回策略（退回到初始节点、退回到上一节点，退回到手选的节点），查找退回指向的节点实例（包括正在运行的），可能有多个
        List<Map<String,Object>> pbToNodeInsList = new ArrayList<Map<String,Object>>();
        if(pbPolicy.equals(FlowType.node_pb_policy_toFirst_eJump) || pbPolicy.equals(FlowType.node_pb_policy_toFirst_eNext)){
            //退回到初始节点
            pbToNodeInsList = coreMapper.USelectList(
                    new DMaker().Selector
                            .putFactorItem("s_type", FlowType.node_type_start)
                            .putFactorItem("flow_id",flow_id)
                            .putFactorItem("flowins_id",flowins_id)
                            .Select("nodeins.node_id,nodeins.id AS nodeins_id,nodeins.status")
                            .From(fw_flow_node.class,"start_node")
                            .innerJoin(fw_flow_line.class,"line","line.start_node = start_node.id")
                            .innerJoin(fw_flowins_node.class,"nodeins","nodeins.node_id = line.end_node AND nodeins.flowins_id= #{flowins_id}","flowins_id")
                            .Where("AND start_node.node_type = #{s_type} AND start_node.flow_id = #{flow_id}","s_type","flow_id")
                            .GetFactor()
            );
        }
        else if(pbPolicy.equals(FlowType.node_pb_policy_toLast_eJump) || pbPolicy.equals(FlowType.node_pb_policy_toLast_eNext)){
            //退回到上一节点
            pbToNodeInsList = coreMapper.USelectList(
                    new DMaker().Selector
                            .putFactorItem("pb_from_node_id",pb_from_node_id)
                            .putFactorItem("flowins_id",flowins_id)
                            .Select("nodeins.node_id,nodeins.id AS nodeins_id,nodeins.status")
                            .From(fw_flow_node.class,"from_node")
                            .innerJoin(fw_flow_line.class,"line","line.end_node = from_node.id")
                            .innerJoin(fw_flowins_node.class,"nodeins","nodeins.node_id = line.start_node AND nodeins.flowins_id= #{flowins_id}","flowins_id")
                            .Where("AND from_node.id = #{pb_from_node_id}","pb_from_node_id")
                            .GetFactor()
            );
        }
        else if(pbPolicy.equals(FlowType.node_pb_policy_toSelected_eJump) || pbPolicy.equals(FlowType.node_pb_policy_toSelected_eNext)){
            //退回到手选的节点
            if(pb_to_nodeins_id!=null && pb_to_nodeins_id.length()>0){
                pb_to_nodeins_id = ','+pb_to_nodeins_id+',';
                pbToNodeInsList = coreMapper.USelectList(
                        new DMaker().Selector
                                .putFactorItem("pb_to_nodeins_id",pb_to_nodeins_id)
                                .putFactorItem("flowins_id",flowins_id)
                                .Select("nodeins.node_id,nodeins.id AS nodeins_id,nodeins.status")
                                .From(fw_flowins_node.class,"nodeins")
                                .Where("AND nodeins.flowins_id= #{flowins_id} AND INSTR(#{pb_to_nodeins_id}, CONCAT(CONCAT(',',nodeins.id),',')) > 0","flowins_id","pb_to_nodeins_id")
                                .GetFactor()
                );
            }
        }
        else if(pbPolicy.equals(FlowType.node_pb_policy_No)){
            String message = "节点禁止退回";
            System.out.println("【AAAA】"+message+" nodeins_id："+nodeins_id);
            return GetResultData("failure",message,null);
        }
        else{
            String message = "不支持的退回策略";
            System.out.println("【AAAA】"+message+"："+pbPolicy);
            return GetResultData("failure",message,null);
        }

        if(pbToNodeInsList.size()==0){
            String message = "未找到退回指向的节点实例";
            System.out.println("【AAAA】"+message);
            return GetResultData("failure",message,null);
        }
        else{
            for(Map<String,Object> pbToNodeIns : pbToNodeInsList){
                if(pbToNodeIns.get("nodeins_id").toString().equals(nodeins_id)){
                    String message = "退回指向的节点实例与发起退回的节点重复";
                    System.out.println("【AAAA】"+message);
                    return GetResultData("failure",message,null);
                }
            }
        }

        int pbToNodeNum = 0;
        List<fw_flowins_node_back> nodeBackinsModelLst = new ArrayList<fw_flowins_node_back>();
        List<fw_flowins_node> pbToNodeinsModelList = new ArrayList<fw_flowins_node>();
        List<fw_flowins_node_user> pbToNodeUserModelList = new ArrayList<fw_flowins_node_user>();
        for(Map<String,Object> pbToNodeIns : pbToNodeInsList){
            String pbToNodeId = pbToNodeIns.get("node_id").toString();
            String pbToNodeInsId = pbToNodeIns.get("nodeins_id").toString();
            String pbToNodeinsStatus = pbToNodeIns.get("status").toString();

            List<Map<String,Object>> pbToNodeDataList = coreMapper.USelectList(
                    new DMaker().Selector
                            .putFactorItem("flowins_id",flowins_id)
                            .putFactorItem("node_id",pbToNodeId)
                            .Select("nodeins.id,nodeins.status")
                            .From(fw_flowins_node.class,"nodeins")
                            .Where("AND nodeins.flowins_id = #{flowins_id} AND nodeins.node_id=#{node_id}","flowins_id","node_id")
                            .GetFactor()
            );
            if(pbToNodeDataList.size()==1){
                pbToNodeNum++;//对于处于运行中的实例，不再次启动，仍计入pbToNodeNum
                if(pbToNodeinsStatus.equals(FlowType.node_status_running)){}
                else{
                    fw_flowins_node pbToNodeinsMode = new fw_flowins_node();
                    pbToNodeinsMode.setId(pbToNodeInsId);
                    pbToNodeinsMode.setStatus(FlowType.node_status_running);
                    pbToNodeinsModelList.add(pbToNodeinsMode);
                    //查找退回指向节点的参与者实例
                    List<Map<String,Object>> pbToNodeUserDataList = coreMapper.USelectList(
                            new DMaker().Selector
                                    .putFactorItem("nodeins_id",pbToNodeInsId)
                                    .Select("person.id,person.status")
                                    .From(fw_flowins_node_user.class,"person")
                                    .Where("AND person.nodeins_id = #{nodeins_id}","nodeins_id")
                                    .GetFactor()
                    );
                    for(Map<String,Object> pbToNodeUserData : pbToNodeUserDataList){
                        if(
                                pbToNodeUserData.get("status")==null
                                        || !(pbToNodeUserData.get("status").toString().equals(FlowType.node_user_status_running))){
                            fw_flowins_node_user pbToNodeUserModel = new fw_flowins_node_user();
                            pbToNodeUserModel.setId(pbToNodeUserData.get("id").toString());
                            pbToNodeUserModel.setStatus(FlowType.node_user_status_running);
                            pbToNodeUserModelList.add(pbToNodeUserModel);
                        }
                    }

                    //退回记录实例
                    fw_flowins_node_back nodeBackinsModel = new fw_flowins_node_back();
                    nodeBackinsModel.setId(UUID.randomUUID().toString());
                    nodeBackinsModel.setStatus(nodeins_id);
                    nodeBackinsModel.setFrom_nodeins(nodeins_id);
                    nodeBackinsModel.setTo_nodeins(pbToNodeInsId);
                    nodeBackinsModel.setStatus(FlowType.node_push_back_status_running);
                    nodeBackinsModel.setText(pb_text);
                    nodeBackinsModel.setSys_createtime(new Date());
                    nodeBackinsModel.setSys_createtimestamp("" + System.currentTimeMillis());
                    nodeBackinsModelLst.add(nodeBackinsModel);
                }
            }
            else if(pbToNodeDataList.size()==0){
                String message = "退回指向的节点未实例化 node_id："+pbToNodeId;
                System.out.println("【AAAA】"+message);
                return GetResultData("failure",message,null);
            }
            else{
                String message = "退回指向的节点，有"+pbToNodeDataList.size()+"个节点实例 node_id："+pbToNodeId;
                System.out.println("【AAAA】"+message);
                return GetResultData("failure",message,null);
            }
        }
        if(pbToNodeNum<=0){
            String message = "未找到退回指向的节点实例";
            System.out.println("【AAAA】"+message);
            return GetResultData("failure",message,null);
        }

        //退回记录实例化
        if(nodeBackinsModelLst.size()>0){ Ctor.HMapper.Save(nodeBackinsModelLst,null); }
        //更新节点状态
        Ctor.HMapper.Upsert(nodeinsWaitingModel);
        fw_flowins_node_log pbNodeLogModel = fTool.CreateNodeLogModel(nodeinsWaitingModel,user_id,0);
        pbNodeLogModel.setPb_text(pb_text);
        Ctor.HMapper.Upsert(pbNodeLogModel);
        if(pbToNodeinsModelList.size()>0){
            Ctor.HMapper.Save(pbToNodeinsModelList,null);
            Ctor.HMapper.Save(fTool.CreateNodeLogModelList(pbToNodeinsModelList,user_id,1),null);
        }
        //更新参与者状态
        if(nUserWaitingModelList.size()>0){ Ctor.HMapper.Save(nUserWaitingModelList,null); }
        if(pbToNodeUserModelList.size()>0){ Ctor.HMapper.Save(pbToNodeUserModelList,null); }

        return GetResultData("success","success",null);
    }

    private HashMap<String,Object> GetResultData(String status,String message,Object data){
        HashMap<String,Object> result = new HashMap<String,Object>();
        result.put("status",status);
        result.put("message",message);
        result.put("data",data);
        return result;
    }

    //查找流程实例的相关数据
    //flow_code,data_id
    @PostMapping("/GetFlowins_Some")
    public Object GetFlowins_Some(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);
        String flow_code  =data.get("flow_code").asText();
        String data_id  =data.get("data_id").asText();

        Map<String,Object> result = new HashMap<String,Object>();

        List<Map<String,Object>> flowinsList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("data_id",data_id)
                        .putFactorItem("flow_code",flow_code)
                        .Select("flowins.*")
                        .From(fw_flowins_yw.class,"yw")
                        .innerJoin(fw_flowins.class,"flowins","flowins.id = yw.flow_id")
                        .Where("and yw.data_id=#{data_id} and yw.flow_code=#{flow_code}","data_id","flow_code")
                        .GetFactor()
        );
        result.put("flowins",flowinsList);
        if(flowinsList.size()!=1){return result;}

        String flowins_id = flowinsList.get(0).get("id").toString();

        List<Map<String,Object>> nodeinsList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("flowins_id",flowins_id)
                        .Select("nodeins.*")
                        .From(fw_flowins_node.class,"nodeins")
                        .Where("and nodeins.flowins_id=#{flowins_id}","flowins_id")
                        .GetFactor()
        );
        result.put("nodeinsList",nodeinsList);

        List<Map<String,Object>> lineinsList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("flowins_id",flowins_id)
                        .Select("lineins.*")
                        .From(fw_flowins_line.class,"lineins")
                        .Where("and lineins.flowins_id=#{flowins_id}","flowins_id")
                        .GetFactor()
        );
        result.put("lineinsList",lineinsList);

        return result;
    }
    //查找流程实例的节点日志等信息,包括退回信息（如果有）
    //flow_code,data_id
    @PostMapping("/GetFlowinsNodeLog")
    public Object GetFlowinsNodeLog(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);
        String flow_code  =data.get("flow_code").asText();
        String data_id  =data.get("data_id").asText();

        List<Map<String,Object>> dataList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("flow_code",flow_code)
                        .putFactorItem("data_id",data_id)
                        .Select("nodeins.id AS nodeins_id,IFNULL(nodeins.status,'nothing') AS nodeins_status,nodeins.title AS nodeins_title,nodeins_log.status,IFNULL(IFNULL(ei.name,uu.nick_name),'?') AS status_user_name,nodeins_log.status_time,nodeins_log.pb_text")
                        .From(fw_flowins_yw.class,"yw")
                        .innerJoin(fw_flowins.class,"flowins","flowins.id = yw.flow_id")
                        .innerJoin(fw_flow.class,"flow","flow.id = flowins.flow_id AND flow.code=#{flow_code}","flow_code")
                        .innerJoin(fw_flowins_node.class,"nodeins","nodeins.flowins_id = flowins.id AND nodeins.node_type='"+FlowType.node_type_normal+"'")
                        .innerJoin(fw_flowins_node_log.class,"nodeins_log","nodeins_log.nodeins_id = nodeins.id")
                        .LeftJoin(sys_user.class,"uu","uu.id = nodeins_log.status_user")
                        .LeftJoin(biz_hrm_ei_basic.class,"ei","ei.emp_code = uu.emp_code")
                        .Where("AND yw.data_id = #{data_id}","data_id")
                        .OrderBy("nodeins_log.status_timestamp,nodeins.remark,nodeins.id")
                        .GetFactor()
        );

        for(Map<String,Object> item : dataList){
            if(item.get("nodeins_status").equals(FlowType.node_status_completed)
                    || item.get("nodeins_status").equals(FlowType.node_status_waiting)){
                item.put("person_names",item.get("status_user_name").toString());
            }
            else{item.put("person_names","");}
        }
        for(int i = dataList.size()-1;i >= 0;i--){
            Map<String,Object> item = dataList.get(i);
            if(!(item.get("person_names").toString().equals(""))){
                for(Map<String,Object> secItem : dataList){
                    if( secItem.get("person_names").toString().equals("")
                            && item.get("nodeins_id").toString().equals(secItem.get("nodeins_id").toString()) ){
                        secItem.put("person_names",item.get("person_names").toString());
                    }
                }
            }
        }
        //对于运行中的节点，实时查找参与者作为处理人
        for(Map<String,Object> item : dataList){
            if(item.get("nodeins_status").equals(FlowType.node_status_running)){
                Map<String,Object> pData = new HashMap<String,Object>();
                pData.put("nodeins_id",item.get("nodeins_id").toString());
                List<Map<String,Object>> checkList = flowMapper.GetUserIdByNodeInsIdAndNodeinsUser(pData);
                String person_names = "";
                for(Map<String,Object> check : checkList){
                    if(!person_names.equals("")){person_names = person_names+",";}
                    person_names = person_names + check.get("ei_name").toString();
                }
                item.put("person_names",person_names);
            }
        }

        return dataList;
    }

    //用户待办
    //pageSize、pageNum
    //user_id，非必填，不传的话就取当前登录用户的id值
    @PostMapping("/GetUserTaskRunning")
    public Object GetUserTaskRunning(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        int pageSize = Integer.parseInt(data.get("pageSize").asText());
        int pageNum = Integer.parseInt(data.get("pageNum").asText());
        int min_index = (pageNum-1) * pageSize;
        int index_num = pageSize;

        String user_id = FlowType.getJsonNodeItemTextNull(data,"user_id");
        user_id = user_id==null?Ctor.getCurrentUserId():user_id;

        Map<String,Object> ff = new HashMap<String,Object>();
        ff.put("user_id",user_id);
        ff.put("min_index",min_index<0?0:min_index);
        ff.put("index_num",index_num<0?0:index_num);
        List<Map<String, Object>> rData = flowMapper.GetUserTaskRunning(ff);
        List<Map<String, Object>> countData = flowMapper.GetUserTaskRunningCount(ff);

        Map<String,Object> result = new HashMap<String,Object>();
        result.put("pagedata",rData);
        result.put("count",Integer.parseInt(countData.get(0).get("count").toString()));

        return result;
    }

    //用户已办
    //pageSize、pageNum
    //user_id，非必填，不传的话就取当前登录用户的id值
    @PostMapping("/GetUserTaskCompleted")
    public Object GetUserTaskCompleted(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }

        int pageSize = Integer.parseInt(data.get("pageSize").asText());
        int pageNum = Integer.parseInt(data.get("pageNum").asText());
        int min_index = (pageNum-1) * pageSize;
        int index_num = pageSize;

        String user_id = FlowType.getJsonNodeItemTextNull(data,"user_id");
        user_id = user_id==null?Ctor.getCurrentUserId():user_id;

        Map<String,Object> ff = new HashMap<String,Object>();
        ff.put("user_id",user_id);
        ff.put("min_index",min_index);
        ff.put("index_num",index_num);
        List<Map<String, Object>> rData = flowMapper.GetUserTaskCompleted(ff);
        List<Map<String, Object>> countData = flowMapper.GetUserTaskCompletedCount(ff);

        Map<String,Object> result = new HashMap<String,Object>();
        result.put("pagedata",rData);
        result.put("count",Integer.parseInt(countData.get(0).get("count").toString()));

        return result;
    }

    //用户发起的流程实例
    //pageSize、pageNum
    //user_id，非必填，不传的话就取当前登录用户的id值
    @PostMapping("/GetFlowinsInfo_InitByUser")
    public Object GetFlowinsInfo_InitByUser(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String user_id = FlowType.getJsonNodeItemTextNull(data,"user_id");
        user_id = user_id==null?Ctor.getCurrentUserId():user_id;

        Map<String,Object> pData = new HashMap<String,Object>();
        pData.put("create_user_id",user_id);

        int pageSize = Integer.parseInt(data.get("pageSize").asText());
        int pageNum = Integer.parseInt(data.get("pageNum").asText());
        int min_index = (pageNum-1) * pageSize;
        int index_num = pageSize;
        pData.put("min_index",min_index<0?0:min_index);
        pData.put("index_num",index_num<0?0:index_num);

        List<Map<String, Object>> rData = flowMapper.GetFlowinsInfo_InitByUser(pData);
        List<Map<String, Object>> countData = flowMapper.GetFlowinsInfo_InitByUser_Count(pData);

        //检查各节点是否为用户的待办节点
        String nodeins_id = ",";
        for(Map<String, Object> rr :rData){
            if(rr.get("nodeins_status").toString().equals("running")){
                nodeins_id = nodeins_id+(rr.get("nodeins_id").toString())+",";
            }
        }
        List<Map<String,Object>> checkList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("nodeins_id",nodeins_id)
                        .Select("DISTINCT person.nodeins_id")
                        .From(fw_flowins_node.class,"nodeins")
                        .innerJoin(fw_flowins_node_user.class,"person","person.nodeins_id = nodeins.id AND person.status='running'")
                        .Where("AND nodeins.status='running' AND INSTR(#{nodeins_id}, CONCAT(CONCAT(',',nodeins.id),',')) > 0","nodeins_id")
                        .GetFactor()
        );
        if(checkList.size()>0){
            for(Map<String, Object> rr :rData){
                String rNodeinsId = rr.get("nodeins_id").toString();
                for(Map<String, Object> cc :checkList){
                    if(rNodeinsId.equals(cc.get("nodeins_id").toString())){
                        if(fTool.IsRunningNodeRunningPerson(rNodeinsId,user_id)){
                            rr.put("preson_status",FlowType.node_user_status_running);
                        }
                    }
                }
            }
        }

        Map<String,Object> result = new HashMap<String,Object>();
        result.put("pagedata",rData);
        result.put("count",Integer.parseInt(countData.get(0).get("count").toString()));

        return result;
    }


    /*
     * 几个用于流程编辑页和流程画布相关的函数
     * */
    @PostMapping("/GetFlowList")
    public Object GetFlowList(@RequestBody String jsonStr) {
        return dfTool.GetFlowList(jsonStr);
    }
    @PostMapping("/GetFlowCodeForCreate")
    public Object GetFlowCodeForCreate(@RequestBody String jsonStr) {
        return dfTool.GetFlowCodeForCreate(jsonStr);
    }
    @PostMapping("/GetSecForm")
    public Object GetSecForm(@RequestBody String jsonStr) {
        return dfTool.GetSecForm(jsonStr);
    }
    @PostMapping("/UpserFlowAndSecForm")
    public Object UpserFlowAndSecForm(@RequestBody String jsonStr) {
        return dfTool.UpserFlowAndSecForm(jsonStr);
    }
    @PostMapping("/UpsertFlowSecForm")
    public Object UpsertFlowSecForm(@RequestBody String jsonStr) {
        return  dfTool.UpsertFlowSecForm(jsonStr);
    }
    @PostMapping("/GetCanvasData")
    public Object GetCanvasData(@RequestBody String jsonStr) {
        return dfTool.GetCanvasData(jsonStr);
    }
    @PostMapping("/SaveCanvasData")
    public Object SaveCanvasData(@RequestBody String jsonStr) {
        return  dfTool.SaveCanvasData(jsonStr);
    }
    @PostMapping("/GetFlowParamList")
    public Object GetFlowParamList(@RequestBody String jsonStr) {
        return dfTool.GetFlowParamList(jsonStr);
    }
    @PostMapping("/UpsertFlowParam")
    public Object UpsertFlowParam(@RequestBody String jsonStr) {
        return dfTool.UpsertFlowParam(jsonStr);
    }
    @PostMapping("/DeleteParam")
    public Object DeleteParam(@RequestBody String jsonStr) {
        return dfTool.DeleteParam(jsonStr);
    }

    /*
    * 下面是流程表单相关的函数
    * */

    @PostMapping("/GetAllFlowCodeWithSecFrom")
    public Object GetAllFlowCodeWithSecFrom(@RequestBody String jsonStr) {
        List<Map<String,Object>> dataList = coreMapper.USelectList(
                new DMaker().Selector
                        .Select("flow.title,flow.code,form.table_name")
                        .From(fw_flow.class,"flow")
                        .innerJoin(fw_flowsec_form.class,"form","form.flow_id = flow.id")
                        .OrderBy("flow.order_number,flow.code")
                        .GetFactor()
        );
        return dataList;
    }

    @PostMapping("/GetFlowsecFormItem")
    public Object GetFlowsecFormItem(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }
        String flow_code = data.get("flow_code").asText();

        List<Map<String,Object>> dataList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("flow_code",flow_code)
                        .Select("form.table_column")
                        .From(fw_flow.class,"flow")
                        .innerJoin(fw_flowsec_form.class,"form","form.flow_id = flow.id")
                        .Where("and flow.code=#{flow_code}","flow_code")
                        .GetFactor()
        );

        return dataList;
    }

    @PostMapping("/GetFlowsecFormItemByNodeinsId")
    public Object GetFlowsecFormItemByNodeinsId(@RequestBody String jsonStr) {
        ObjectMapper mapper = new ObjectMapper();
        ObjectNode data = null;
        try{
            data = (ObjectNode)mapper.readTree(jsonStr);
        }
        catch (IOException e) {
            e.printStackTrace();
            return GetResultData("failure","wrong jsonStr",null);
        }
        String flow_code = data.get("flow_code").asText();
        String type = data.get("type").asText();
        String nodeins_id = null;
        if(type.equals("edit")){
            nodeins_id = data.get("nodeins_id").asText();
        }

        Map<String,Object> result = new HashMap<String,Object>();

        List<Map<String,Object>> dataList = coreMapper.USelectList(
                new DMaker().Selector
                        .putFactorItem("flow_code",flow_code)
                        .Select("form.table_column")
                        .From(fw_flow.class,"flow")
                        .innerJoin(fw_flowsec_form.class,"form","form.flow_id = flow.id")
                        .Where("and flow.code=#{flow_code}","flow_code")
                        .GetFactor()
        );
        result.put("data",dataList);

        if(type.equals("template") || type.equals("show")){}
        else if(type.equals("create") || (type.equals("edit") && nodeins_id.equals("nothing"))){
            List<Map<String,Object>> nDataList = coreMapper.USelectList(
                    new DMaker().Selector
                            .Select("node.ee_ff_item")
                            .putFactorItem("flow_code",flow_code)
                            .From(fw_flow.class,"flow")
                            .innerJoin(fw_flow_node.class,"s_node","s_node.flow_id = flow.id and s_node.node_type = 'start'")
                            .innerJoin(fw_flow_line.class,"line","line.start_node = s_node.id")
                            .innerJoin(fw_flow_node.class,"node","line.end_node = node.id")
                            .Where("and flow.code=#{flow_code}","flow_code")
                            .GetFactor()
            );
            result.put("node_data",nDataList);
        }
        else if(type.equals("edit")){
            List<Map<String,Object>> nDataList = coreMapper.USelectList(
                    new DMaker().Selector
                            .putFactorItem("nodeins_id",nodeins_id)
                            .Select("node.ee_ff_item")
                            .From(fw_flowins_node.class,"nodeins")
                            .innerJoin(fw_flow_node.class,"node","node.id = nodeins.node_id")
                            .Where("and nodeins.id=#{nodeins_id}","nodeins_id")
                            .GetFactor()
            );
            result.put("node_data",nDataList);
        }

        return result;
    }

    //flow_code、id
    @PostMapping("/FlowsecFormItem_SelectOne")
    public Object FlowsecFormItem_SelectOne(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String flow_code = data.get("flow_code").asText();
        String id = data.get("id").asText();

        List<Map<String,Object>> checkList = Ctor.CoreMapper.USelect(
                Ctor.DMaker().Selector
                        .putFactorItem("flow_code",flow_code)
                        .Select("ff.table_name")
                        .From(fw_flow.class,"flow")
                        .innerJoin(fw_flowsec_form.class,"ff","ff.flow_id = flow.id")
                        .Where("and flow.code = #{flow_code}","flow_code")
                        .GetFactor());
        if(checkList.size()!=1){return null;}

        Map<String,Object> pData = new HashMap<String,Object>();
        pData.put("table_name",checkList.get(0).get("table_name").toString());
        pData.put("id",id);
        pData.put("min_index",0);
        pData.put("index_num",1);

        pData.put("flow_code",flow_code);
        List<Map<String, Object>> rData = flowMapper.FlowSecFormTable_Select(pData);
        if(rData.size()==0){return  null;}

        return rData.get(0);
    }

    //flow_code
    @PostMapping("/FlowsecFormItem_GetData")
    public Object FlowsecFormItem_GetData(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String flow_code = data.get("flow_code").asText();
        String user_id = Ctor.getCurrentUserId();//当前登录用户id

        String table_name = fTool.FlowsecFormItem_GetTableName(flow_code);

        Map<String,Object> pData = new HashMap<String,Object>();
        pData.put("table_name",table_name);

        if(data.has("select_all") && "yes".equals(FlowType.getJsonNodeItemTextNull(data,"select_all"))){}
        else{
            pData.put("create_user_id",user_id);//只查找用户创建的记录
        }


        if(table_name==null || table_name.equals("")){return new ArrayList<>();}

        int pageSize = Integer.parseInt(data.get("pageSize").asText());
        int pageNum = Integer.parseInt(data.get("pageNum").asText());
        int min_index = (pageNum-1) * pageSize;
        int index_num = pageSize;
        pData.put("min_index",min_index<0?0:min_index);
        pData.put("index_num",index_num<0?0:index_num);

        for(int i=1;i<30;i++){
            String col_name = "col_"+i;
            if(data.has(col_name)){
                pData.put(col_name,data.get(col_name).asText());;
            }
        }

        pData.put("flow_code",flow_code);
        List<Map<String, Object>> rData = flowMapper.FlowSecFormTable_Select(pData);
        List<Map<String, Object>> countData = flowMapper.FlowSecFormTable_Select_Count(pData);

        //for(Map<String>){}

        //关联用户和部门数据（如果有对应的表单项）
        rData  =fTool.attachSecFromSomeInfo(flow_code,rData);

        //关联流程数据
        rData =fTool.attachUserTask(flow_code,user_id,rData,100,1);

        Map<String,Object> result = new HashMap<String,Object>();
        result.put("pagedata",rData);
        result.put("count",Integer.parseInt(countData.get(0).get("count").toString()));

        return result;
    }

    //flow_code
    @PostMapping("/FlowsecFormItem_GetTask")
    public Object FlowsecFormItem_GetTask(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String flow_code = data.get("flow_code").asText();
        String user_id = Ctor.getCurrentUserId();//当前登录用户id

        String table_name = fTool.FlowsecFormItem_GetTableName(flow_code);
        if(table_name==null || table_name.equals("")){return new ArrayList<>();}

        Map<String,Object> pData = new HashMap<String,Object>();
        pData.put("flow_code",flow_code);
        pData.put("table_name",table_name);
        pData.put("user_id",user_id);

        int pageSize = Integer.parseInt(data.get("pageSize").asText());
        int pageNum = Integer.parseInt(data.get("pageNum").asText());
        int min_index = (pageNum-1) * pageSize;
        int index_num = pageSize;
        pData.put("min_index",min_index<0?0:min_index);
        pData.put("index_num",index_num<0?0:index_num);

        for(int i=1;i<30;i++){
            String col_name = "col_"+i;
            if(data.has(col_name)){
                pData.put(col_name,data.get(col_name).asText());;
            }
        }

        List<Map<String, Object>> rData = flowMapper.FlowSecFormTable_Select_GetTask(pData);
        List<Map<String, Object>> countData = flowMapper.FlowSecFormTable_Select_GetTaskCount(pData);

        //关联用户和部门数据（如果有对应的表单项）
        rData  =fTool.attachSecFromSomeInfo(flow_code,rData);

        //关联流程数据
        rData =fTool.attachUserTask(flow_code,user_id,rData,100,1);

        Map<String,Object> result = new HashMap<String,Object>();
        result.put("pagedata",rData);
        result.put("count",Integer.parseInt(countData.get(0).get("count").toString()));

        return result;
    }

    //flow_code,id
    @PostMapping("/FlowsecFormItem_Delete")
    public Object FlowsecFormItem_Delete(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String flow_code = data.get("flow_code").asText();
        String id = data.get("id").asText();

        String table_name = fTool.FlowsecFormItem_GetTableName(flow_code);
        if(table_name==null || table_name.equals("")){return false;}

        Map<String,Object> pData = new HashMap<String,Object>();
        pData.put("table_name",table_name);
        pData.put("id",id);
        flowMapper.FlowSecFormTable_Delete(pData);

        fTool.DeleteFlowins(id);

        return true;
    }

    //flow_code
    @PostMapping("/FlowsecFormItem_Upsert")
    public Object FlowsecFormItem_Upsert(@RequestBody String jsonStr) {
        ObjectNode data = Ctor.getObjectNode(jsonStr);

        String id = data.get("id").asText();
        String flow_code = data.get("flow_code").asText();
        String user_id = Ctor.getCurrentUserId();//当前登录用户id

        String table_name = fTool.FlowsecFormItem_GetTableName(flow_code);
        if(table_name==null || table_name.equals("")){return false;}

        Map<String,Object> pData = new HashMap<String,Object>();

        pData.put("id",id);

        Map<String,Object> ccData = new HashMap<String,Object>();
        ccData.put("id",id);
        ccData.put("id",id);
        ccData.put("table_name",table_name);
        ccData.put("min_index",0);
        ccData.put("index_num",1);
        ccData.put("flow_code",flow_code);
        List<Map<String, Object>> rData = flowMapper.FlowSecFormTable_Select(ccData);
        if(rData.size()==0){
            System.out.println("【Create SecFromTable Model】 "+id);
            pData.put("sys_createuser",user_id);
        }
        else{
            System.out.println("【Upsert SecFromTable Model】 "+id);
        }

        for(int i=1;i<30;i++){
            String col_name = "col_"+i;
            String col_value = FlowType.getJsonNodeItemTextNull(data,col_name);
            if(data.has(col_name) && col_value!=null){
                pData.put(col_name,col_value);
            }
        }

        Ctor.HMapper.Upsert(table_name,pData);

        //更新子表
        if (data.has("reims") && data.get("reims").size() > 0) {
            Ctor.HMapper.Save(fw_com_sub.class, (ArrayNode) data.get("reims"),
                    Ctor.DMaker().Deleter
                            .putFactorItem("biz_id", id)
                            .From(fw_com_sub.class)
                            .Where("and biz_id=#{biz_id}","biz_id")
                            .GetFactor());
        }

        return true;
    }

    @PostMapping("/GetFWComSub")
    public Object GetData(@RequestBody String jsonStr) {
        List<?> ret = Ctor.CoreMapper.USelect(
                Ctor.DMaker(jsonStr).Selector
                        .From(fw_com_sub.class)
                        .Where("and biz_id=#{biz_id}","biz_id")
                        .GetFactor());
        return JsonResult(ret);
    }

    ///////

}
